package com.licq.ldoc.parser.impl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.licq.ldoc.config.Configuration;
import com.licq.ldoc.domain.Attribute;
import com.licq.ldoc.domain.AttributeElement;
import com.licq.ldoc.domain.Element;
import com.licq.ldoc.utils.ClassUtils;

/**
 * 
 * @author liujian
 *
 * @param <T>
 */
public abstract class AbstractElementParser<T> extends AbstractParser<T> {

	private static transient Log logger = LogFactory.getLog(AbstractElementParser.class);

	protected void parseFields(Class<?> clazz, Element element) {
	    Collection<Field> fields = getAllDeclaredFieldsSorted(clazz);
	    for (Field field : fields) {
	        parseField(field, element);
	    }
	}

	private void parseField(Field field, Element element) {
		if (isSimpleType(field)) {
			Attribute attribute = AttributeParser.parse(field);
			if (!attribute.isIgnored()) {
				element.addAttribute(attribute);
			}
		} else {
			AttributeElement attributeElement = AttributeElementParser.parse(field);
			if (!attributeElement.isIgnored()) {
				element.addAttributeElement(attributeElement);
			}
		}
	}

	private Collection<Field> getAllDeclaredFieldsSorted(Class<?> clazz) {
		List<Field> fields = new ArrayList<Field>(ClassUtils.getAllDeclaredFields(clazz, 
				getUntilClazz(), true));
		Collections.sort(fields, new Comparator<Field>() {
			@Override
			public int compare(Field o1, Field o2) {
				if (isSimpleType(o1) && isSimpleType(o2)) {
					return 0;
				}
				return isSimpleType(o1) ? -1 : isSimpleType(o2) ? 1 : 0;
			}
		});
		return fields;
	}

	/**
	 * 是否为简单类型(不涉及自定义类型的字段类型)
	 * @param field
	 * @return
	 */
	private boolean isSimpleType(Field field) {
		return ClassUtils.isBasicJavaType(field.getType())
				|| ClassUtils.isBasicJavaTypeWrapper(field)
				|| ClassUtils.isEnum(field.getType())
				|| ClassUtils.isEnumWrapper(field)
				|| ClassUtils.isBasicJavaTypeMapper(field);
	}

	private Class<?> getUntilClazz() {
		String utilClazz = null;
		try {
			utilClazz = Configuration.getConfiguration().getString("utilClazz");
			return Class.forName(utilClazz);
		} catch (ClassNotFoundException e) {
			if (logger.isInfoEnabled()) {
				logger.info(String.format("util class[%s] is not found.", utilClazz));
			}
		}
		return null;
	}

	

}
